// movietheatre.cc

#include "copyright.h"
#include "system.h"
#include "synch.h"

//----------------------------
// TICKET CLERK IMPLEMENTATION
//----------------------------

#define BUSY 1
#define FREE 0
#define BREAK 2
#define NOBREAK 3
#define MAX_TC 3
#define MAX_CC 3
#define MAX_TT 3
#define NOCLERK -1
#define TICKETPRICE 12
#define FOODPRICE 5
#define SODAPRICE 4
#define STOP_TAKE_TICKET 4
#define WAIT_FOR_TAKING_TICKETS 0
#define DONE_TAKING_TICKETS 1
#define CINEMACAPACITY 25
#define TT_YIELD_TIME 6
#define MAX_LINE_LENGTH 256
#define MGR_WAIT_LONG_TIME 6
#define NUM_GROUPS 10
#define GROUP_SIZE 5
#define ABSENT 44
#define QUEUE_LEN_GET_CLERK_BACK 5  //when people in queue is more than QUEUE_LEN_GET_CLERK_BACK, manager will get sb back

int is_ALL_TT_Queue_Still_Empty = 0;// each time check, will increase if empty

int NumOfOccupiedSeat = 0; //updated by customers only when they sit
int Customer_Seats_Lock; //Lock to protect seats


int NextMovieIsReady_Customer_CV; //Manager tell customer in lobby to come and check tickets
int Customer_Lobby_Lock; //Lock the customer by Lobby door
int SeatPosition[5][5]; //by acquire ticketTakerSeatLock : 0 is EMPTY  &&  1 is OCCUPIED
int Do_We_Find_Another_TT;


//----------------------------
// MOVIE TECHNICIAN IMPLEMENTATION
//----------------------------

int managerTellsMT_startMovie_CV;
int managerTellsMT_startMovieLock;


int MovieBeginCV;
int Customer_MovieBegin_Lock;

int MovieEndCV;
int Customer_MovieEnd_Lock;


//----------------------------
// TICKET TAKER IMPLEMENTATION
//----------------------------

int ticketTakerCV[MAX_TT];
int ticketTakerLock[MAX_TT];

int ticketTakerLineCV[MAX_TT];
int ticketTakerLineLock;

int ticketTakerSeatLock;
int seatLeft; //by acquire TicketTaker_Seat_Lock


int startTakingTicketCV;//for stop
int startTakingTicketLock;


int ticketTakerLineCount[MAX_TT];
int ticketTakerState[MAX_TT];

// Manager to Ticket Taker Interaction
int MgrTTCondition;
int MgrTTLock;
int MgrTTNote[MAX_TT];				 //Manager leaves a note to tell him to break
int numberTicketsPerTicketTaker[MAX_TT];

//----------------------------
// TICKET CLERK IMPLEMENTATION
//----------------------------
// Manager to Ticket Clerk Interaction
int MgrTCLock;
int MgrTCCondition;
int MgrTCNote[MAX_TC];


int ticketClerkCV[MAX_TC];
int ticketClerkLock[MAX_TC];
int ticketClerkState[MAX_TC];

int ticketClerkLineCount[MAX_TC];
int ticketClerkLineLock;
int ticketClerkLineCV[MAX_TC];

int numberTicketsPerTicketClerk[MAX_TC];
int ticketsSoldPerTicketClerk[MAX_TC];
int concessionPerConcessionClerk[MAX_CC];



//----------------------------
// CONCESSION CLERK IMPLEMENTATION
//----------------------------

// Manager to Concession Clerk Interaction
int MgrCCLock;
int MgrCCCondition;
int MgrCCNote[MAX_CC];

int concessionClerkCV[MAX_CC];
int concessionClerkLock[MAX_CC];
int concessionClerkState[MAX_CC];

int concessionClerkLineCount[MAX_CC];
int concessionClerkLineLock;
int concessionClerkLineCV[MAX_CC];

int foodQtyPerConcessionClerk[MAX_CC];
int sodaQtyPerConcessionClerk[MAX_CC];

int ticketClerkCounter;int concessionClerkCounter;int ticketTakerCounter;int customerCounter;

int ticketClerkCounterLock;int concessionClerkCounterLock;int ticketTakerCounterLock;int customerCounterLock;


//-------------------------
// CUSTOMER IMPLEMENTATION
//-------------------------

struct GroupData {
	int event;
	int lock;
	Semaphore *semaphore;
	int food;
	int soda;
	int ticketsTaken;
	int seatPositionForGroup[GROUP_SIZE][2];
}; 

struct CustomerData {
	int customerNumber;
	int groupNumber;
	int groupSize; //Only head customers need this value
	GroupData *custGroupData;
};

void PickUpSeats(int SeatArray[][5], int row, int column, int ourGroupSize, int seatPickUp[][2]){

}

/*void PickUpSeats(int SeatArray[][5], int row, int column, int ourGroupSize, int seatPickUp[][2]){

//for consecutive seats
int countConsecutiveSeats = 0;//Count num of consecutive seats each row
int HeadOfPreferedColumn  = -1;//for pick up consecutive seat

//for unconsecutive seats on the same row
int countFreeSeatsOneRow = 0;//Count num of free seats each row
int HeadOfPreferedSameRow = -1;

//for consecutive rows
int countConsecutiveRows = 0;
int HeadOfPreferedConsecutiveRows = -1;

int countForSeatsPickedUp = 0;//temp count
int i, j, k;

int seatPickUpPosition = 0;
//Try to seat on the same row, consecutive prefered
for(i = 0; i < row; i++){
countFreeSeatsOneRow = 0;
countConsecutiveSeats = 0;
for(j = 0; j < column; j++){
if(SeatArray[i][j] != 0){
countConsecutiveSeats = 0;
HeadOfPreferedColumn  = -1;
}
else{
if(countConsecutiveSeats == 0) {//means the begin column of the consecutive seats
HeadOfPreferedColumn  = j;
}
countFreeSeatsOneRow += 1;
countConsecutiveSeats += 1;
}
}
if(countFreeSeatsOneRow >= ourGroupSize) { HeadOfPreferedSameRow = j; } //seats on the same row
if(countConsecutiveSeats >= ourGroupSize){ //consecutive seats on same row

if(HeadOfPreferedColumn  == -1){
//Print("Seats Pick ERROR: HeadOfPreferedColumn  == -1^");
break;
}

//Pick Up Consecutive Seats on One Line
countForSeatsPickedUp = 0;
for(k = HeadOfPreferedColumn ; k < column && countForSeatsPickedUp < ourGroupSize; k++,ourGroupSize++){
if(SeatArray[i][k] > 0){
//Print("Seats Pick ERROR: choose an occupied seat^");
break;
}
SeatArray[i][k] += 1;

//records the picked up seats
seatPickUp[seatPickUpPosition][0] = i;
seatPickUp[seatPickUpPosition][1] = k;
seatPickUpPosition++;
}

return;
}

//count consecutive row

if(countFreeSeatsOneRow == 0){ // no consecutive for this row
countConsecutiveRows = 0;
HeadOfPreferedConsecutiveRows = -1;
}
else if(countConsecutiveRows < ourGroupSize) {
if(countConsecutiveRows == 0){ // count the first time
HeadOfPreferedConsecutiveRows = i;
}
countConsecutiveRows += countFreeSeatsOneRow;
}
}


//loop out, means found no consecutive seats, so we choose to be the same line at least.
if(HeadOfPreferedSameRow >= 0){
countForSeatsPickedUp = 0;
for(i = HeadOfPreferedSameRow, j = 0; j < column; j++){
if(SeatArray[i][j] == 0){
SeatArray[i][j] += 1;
countForSeatsPickedUp += 1;

//records the picked up seats
seatPickUp[seatPickUpPosition][0] = i;
seatPickUp[seatPickUpPosition][1] = j;
seatPickUpPosition++;

if(countForSeatsPickedUp >= ourGroupSize)
return;
}
}
}

ELSE, Try to seat on consecutive row
else if(HeadOfPreferedConsecutiveRows >= 0){
countForSeatsPickedUp = 0;
for(i = HeadOfPreferedConsecutiveRows; i < row; i++){
for(j = 0; j < column; j++){
if(SeatArray[i][j] == 0){
SeatArray[i][j] += 1;
countForSeatsPickedUp += 1;

//records the picked up seats
seatPickUp[seatPickUpPosition][0] = i;
seatPickUp[seatPickUpPosition][1] = j;
seatPickUpPosition++;

if(countForSeatsPickedUp >= ourGroupSize)
return;
}
}
}
}

IF NOT, We have to find any seat available
else{
countForSeatsPickedUp = 0;
for(i = 0; i < row; i++){
for(j = 0; j < column; j++){
if(SeatArray[i][j] == 0){
SeatArray[i][j] += 1;
countForSeatsPickedUp += 1;

//records the picked up seats
seatPickUp[seatPickUpPosition][0] = i;
seatPickUp[seatPickUpPosition][1] = j;
seatPickUpPosition++;

if(countForSeatsPickedUp >= ourGroupSize)
return;
}
}
}
}
}*/



void PlayMovie()
{
	//Print("Movie play started^");
	int movieYields = rand()%100 + 200; //this is number of hours movie should be run before being stopped

	for (int num = 0; num < movieYields ; num++)
	{
		Yield();
	}

	//Print("^ Movie finished successfully here ^");
}

void GoToLobby(CustomerData *custDat) {
	Print("Customer % in Group % is in the lobby.^", 39, custDat->customerNumber, custDat->groupNumber);
}
void LeavingLobby(CustomerData *custDat){
	Print("Customer % in Group % is leaving the lobby.^", 44, custDat->customerNumber, custDat->groupNumber);
}
void BeginWatchMovie() {
	//Print("Customer begin watching movie");
}

void checkTicket(CustomerData *custData){			//add1
	int groupSize = custData->groupSize;
	int customerNumber = custData->customerNumber;
	int groupNumber = custData->groupNumber;
	//See if there is ticketTaker -- TICKET TAKER AVAILABILITY
	//If no, we wait for NoTiketTakerErrorCondition

	if(groupSize > 0){
		//********** It is leader

		Print("Customer % in Group % start checking tickets^", 45, custData->customerNumber,  custData->groupNumber);

		//-------------BEFORE ENTERING CINEMA--------------//
		if(custData->groupNumber == 9){//bad
			Print("330@@@@@@@@@@@@@@@@@@@@@@Group 9 is here^", 41, 0, 0);
		}
		/**check if TT is on break**/
		Do_We_Find_Another_TT = 1;
		while(Do_We_Find_Another_TT){ // when the TT I wait is on break, I need to find another line
			AcquireLock(ticketTakerLineLock);

			if(custData->groupNumber == 9){//bad
				Print("338@@@@@@@@@@@@@@@@@@@@@@Group 9 - 2 is here^", 45, 0, 0);
			}
			/**chose the shortest line**/
			int shortestTTLine = -1;
			int shortestTTLineLength = MAX_LINE_LENGTH;
			int i;

			//check if any TT arrive yet
			for(i = 0; i < MAX_TT; i++){
				if(ticketTakerState[i]!=ABSENT){
					shortestTTLine = 0;
					break;
				}
			}

			if(shortestTTLine < 0){ //All TT haven't come yet
				//Print("TT has not come!^");
				for(i = 0; i < 5; i++){
					Yield();
				}
				continue;
			}

			if(custData->groupNumber == 9){//bad
				Print("362@@@@@@@@@@@@@@@@@@@@@@Group 9 is here^", 41, 0, 0);
			}

			//find the line
			for (i=0; i< MAX_TT ; i++) {
				//Print("TT % state % count % ^",i,ticketTakerState[i], ticketTakerLineCount[i]);
				// check for Available Ticket Taker with the shortest length
				if(ticketTakerState[i] == FREE){
					shortestTTLineLength = ticketTakerLineCount[i];
					shortestTTLine = i;
					break;
				}
				if ((shortestTTLineLength >= ticketTakerLineCount[i]) && ticketTakerLineCount[i] > 0 &&
					(ticketTakerState[i] != BREAK && ticketTakerState[i] != STOP_TAKE_TICKET)) {
						shortestTTLineLength = ticketTakerLineCount[i];
						shortestTTLine = i;
				}
			}


			if(custData->groupNumber == 9){//bad
				Print("383@@@@@@@@@@@@@@@@@@@@@@Group 9 is here^", 41, 0, 0);
			}


			//Print("In checktickets : Head % acquired lock for TT %^", custData->groupNumber, shortestTTLine);
			if(shortestTTLineLength >0){
				ticketTakerLineCount[shortestTTLine]++;
				//keep
				//Print("Customer % in Group % is getting in TicketTaker line %^",custData->customerNumber,  custData->groupNumber, shortestTTLine);
				/**wait for queue**/
				WaitCV(ticketTakerLineCV[shortestTTLine],ticketTakerLineLock);

				/**check if stop taking tickets**/
				if(ticketTakerState[shortestTTLine] == STOP_TAKE_TICKET){
					if(custData->groupNumber == 9){//bad
						Print("398@@@@@@@@@@@@@@@@@@@@@@Group 9 is here^", 41, 0, 0);
					}
					//keep
					//Print("Customer % in Group % sees TicketTaker % is no longer taking tickets^",custData->customerNumber,  custData->groupNumber, shortestTTLine);
					//Print("Stop TT % ^", shortestTTLine);
					custData->custGroupData->ticketsTaken = WAIT_FOR_TAKING_TICKETS;
					custData->custGroupData->lock->AcquireLock();
					custData->custGroupData->event->BroadcastCV(custData->custGroupData->lock);
					custData->custGroupData->lock->ReleaseLock();
					GoToLobby(custData);
					AcquireLock(Customer_Lobby_Lock);		//Lobby
					WaitCV(NextMovieIsReady_Customer_CV,Customer_Lobby_Lock);
					LeavingLobby(custData);
					ReleaseLock(Customer_Lobby_Lock);
					Do_We_Find_Another_TT = 1;  //add1
					continue;
				}

				/**check if on break**/
				else if(ticketTakerState[shortestTTLine] == BREAK){
					Do_We_Find_Another_TT = 1;
					//keep
					//Print("Customer % in Group % sees TicketTaker % is on break.^",custData->customerNumber,  custData->groupNumber, shortestTTLine);
					if(custData->groupNumber == 9){//bad
						Print("422@@@@@@@@@@@@@@@@@@@@@@Group 9 is here^", 41, 0, 0);
					}
					continue;
				}
				else{
					Do_We_Find_Another_TT = 0;
					if(custData->groupNumber == 9){//bad
						Print("429@@@@@@@@@@@@@@@@@@@@@@Group 9 is here^", 41, 0, 0);
					}
				}
			}
			else{ //TT IS FREE
				ticketTakerLineCount[shortestTTLine]++;
				Do_We_Find_Another_TT = 0;
				if(custData->groupNumber == 9){//bad
					Print("437@@@@@@@@@@@@@@@@@@@@@@Group 9 is here^", 41, 0, 0);
				}
			}


			/**wait for interation with TT**/
			AcquireLock(ticketTakerLock[shortestTTLine]);
			if(custData->groupNumber == 9){//bad
				Print("445@@@@@@@@@@@@@@@@@@@@@@Group 9 is here^", 41, 0, 0);
			}
			ReleaseLock(ticketTakerLineLock);
			//Signal the TT on the TicketTaker lock

			//keep
			//Print("Customer % in Group % is walking up to TicketTaker % to give % tickets^",custData->customerNumber,  custData->groupNumber, shortestTTLine,custData->groupSize);
			numberTicketsPerTicketTaker[shortestTTLine] = custData->groupSize;

			SignalCV(ticketTakerCV[shortestTTLine],ticketTakerLock[shortestTTLine]);

			/**give the ticket and wait for passing into cinema**/
			//Print("Head % checking tickets with TT  % ^", custData->groupNumber, shortestTTLine);
			WaitCV(ticketTakerCV[shortestTTLine],ticketTakerLock[shortestTTLine]);
			if(custData->groupNumber == 9){//bad
				Print("457@@@@@@@@@@@@@@@@@@@@@@Group 9 is here^", 41, 0, 0);
			}
			if(ticketTakerState[shortestTTLine] == STOP_TAKE_TICKET){
				//Print("TT state inside stop = %^",ticketTakerState[shortestTTLine]);
				//keep
				//Print("Customer % in Group % sees TicketTaker % is no longer taking tickets^",custData->customerNumber,  custData->groupNumber, shortestTTLine);

				GoToLobby(custData);
				custData->custGroupData->ticketsTaken = WAIT_FOR_TAKING_TICKETS;
				custData->custGroupData->lock->AcquireLock();
				custData->custGroupData->event->BroadcastCV(custData->custGroupData->lock);
				custData->custGroupData->lock->ReleaseLock();
				AcquireLock(Customer_Lobby_Lock);
				WaitCV(NextMovieIsReady_Customer_CV,Customer_Lobby_Lock);//Lobby
				LeavingLobby(custData);
				ReleaseLock(Customer_Lobby_Lock);
				Do_We_Find_Another_TT = 1;
				continue;
			}
			else{
				//keep
				//Print("Customer % in Group % is leaving TicketTaker %^",custData->customerNumber,  custData->groupNumber, shortestTTLine);

				//Print("Head % broadcasting all the members  ^", custData->groupNumber);
				custData->custGroupData->lock->AcquireLock();
				custData->custGroupData->event->BroadcastCV(custData->custGroupData->lock);
				custData->custGroupData->lock->ReleaseLock();
			}
			//Print("Head % done checking with TT  % ^", custData->groupNumber, shortestTTLine);

			ReleaseLock(ticketTakerLock[shortestTTLine]);

			break;
		}

		//finish Check Ticket, Now go into the cinema
		//Customer [customerNumber] in Group [groupNumber] has entered the movie theater
		//Print("Customer % in Group % has entered the movie theater^", customerNumber, groupNumber);
		Print("Customer % in Group % finish checking tickets^", 46, custData->customerNumber,  custData->groupNumber);
	}
	else{                                                                                                     //add1
		// **********it is member                                                                                 //add1
		//Leader Check with TT                                                                                //add1
		int IS_TT_STOP = 1;                                                                               //add1
		while(IS_TT_STOP){                                                                                    //add1
			custData->custGroupData->lock->AcquireLock();                                                         //add1
			//wait for leader to tell whether TT is stop                                                      //add1
			custData->custGroupData->event->WaitCV(custData->custGroupData->lock);                              //add1
			if (custData->custGroupData->ticketsTaken == WAIT_FOR_TAKING_TICKETS){                            //add1
				//Go to lobby                                                                                 //add1
				custData->custGroupData->lock->ReleaseLock();                                                     //add1
				//Print("Customer % in lobby^",custData->customerNumber);                                    //add1
				//GoToLobby(custData);                                                                                //add1
				AcquireLock(Customer_Lobby_Lock);            //Lobby                                                   //add1
				WaitCV(NextMovieIsReady_Customer_CV,Customer_Lobby_Lock);                                      //add1
				LeavingLobby(custData);										                                  //add1
				ReleaseLock(Customer_Lobby_Lock);                                                               //add1
				//add1
			}                                                                                                 //add1
			else{                                                                                             //add1
				IS_TT_STOP = 0;                                                                           //add1
				break;                                                                                        //add1
			}                                                                                                 //add1
			//add1
		}                                                                                                     //add1
		//finish Check Ticket, Now go into the cinema                                                         //add1
		//Customer [customerNumber] in Group [groupNumber] has entered the movie theater                      //add1
		////Print("Customer % in Group % has entered the movie theater", customerNumber, groupNumber);         //add1
	}                                                                                                         //add1

}

void buyFoodSoda(int headData) {
	//Print("Headbuying food soda^");
	CustomerData* headDat = (CustomerData*)headData;
	//Print("Head Customer ready to buy food ^");
	int availConcessionClerk = NOCLERK;

	// Check if Ticket Clerk is available
	//Print("Head Customer looking for free CC ^");

	while (availConcessionClerk == NOCLERK) {

		AcquireLock(concessionClerkLineLock);
		////Print("Head % acquired Ticket Lock ^", headDat->groupNumber);
		int shortestCCLine = 0;
		int shortestCCLineLength = 256;
		////Print("Head %^",headDat->groupNumber);
		for (int i=0; i< MAX_CC ; i++) {
			// check for Available Ticket Clerk with the shortest length
			if ((shortestCCLineLength >= concessionClerkLineCount[i]) && 
				(concessionClerkState[i] != BREAK)) {
					shortestCCLineLength = concessionClerkLineCount[i];
					shortestCCLine = i;
			}
		}
		// shortest line found

		availConcessionClerk = shortestCCLine;
		if ( availConcessionClerk != NOCLERK) {

			concessionClerkLineCount[availConcessionClerk]++;
			if (shortestCCLineLength >0) {
				//Print("Head % acquired Concession Clerk % Lock ^", headDat->groupNumber,availConcessionClerk);
				//keep
				//Print("Customer % in Group % is getting in ConcessionClerk line %^",headDat->customerNumber,  headDat->groupNumber, availConcessionClerk);

				WaitCV(concessionClerkLineCV[availConcessionClerk],concessionClerkLineLock);
			}
			if ( concessionClerkState[availConcessionClerk] != BREAK) {

				//ticketClerkLineCount[availTicketClerk]++;
				ReleaseLock(concessionClerkLineLock);
				// Once woken up by the Ticket Clerk, buy tickets
				//Print("Head acquiring CC Lock^");
				AcquireLock(concessionClerkLock[availConcessionClerk]);
				//Print("Head % passing on CC the food soda order ^",headDat->groupNumber);
				//numberTicketsPerTicketClerk[availTicketClerk] = headDat->groupSize;
				foodQtyPerConcessionClerk[availConcessionClerk] = headDat->custGroupData->food ;
				sodaQtyPerConcessionClerk[availConcessionClerk] = headDat->custGroupData->soda;

				//keep
				//Print("Customer % in Group % is walking up to ConcessionClerk % to buy % popcorn and % soda^",headDat->customerNumber,  headDat->groupNumber, availConcessionClerk,headDat->groupSize,headDat->custGroupData->food,headDat->custGroupData->soda);

				SignalCV(concessionClerkCV[availConcessionClerk],concessionClerkLock[availConcessionClerk]);
				// after passing on the ticket number, head customer waits

				WaitCV(concessionClerkCV[availConcessionClerk],concessionClerkLock[availConcessionClerk]);
				//keep
				//Print("Customer % in Group % in ConcessionClerk line % is paying % for food^",headDat->customerNumber,  headDat->groupNumber, availConcessionClerk,headDat->custGroupData->food*TICKETPRICE);
				//keep
				//Print("Customer % in Group % is leaving ConcessionClerk %^",headDat->customerNumber,  headDat->groupNumber, availConcessionClerk);

				ReleaseLock(concessionClerkLock[availConcessionClerk]);
			}
			else {
				//Print("**Head % searching again as CC % on break ^", headDat->groupNumber,availConcessionClerk);
				//keep
				//Print("Customer % in Group % sees ConcessionClerk % is on break.^",headDat->customerNumber,  headDat->groupNumber, availConcessionClerk);

				availConcessionClerk = NOCLERK;
				ReleaseLock(concessionClerkLineLock);
			}
		}
		else {
			//Print("No CC found ^ ");
			//shortestTCLineLength = ticketClerkLineCount[0];
			ReleaseLock(concessionClerkLineLock);
		}

	}//while
}

void buyTickets(int headData) {

	CustomerData* headDat = (CustomerData*)headData;
	//Print("Head Customer ready to buy tickets ^");
	int availTicketClerk = NOCLERK;

	// Check if Ticket Clerk is available
	//Print("Head Customer looking for free TC ^");

	while (availTicketClerk == NOCLERK) {

		AcquireLock(ticketClerkLineLock);
		////Print("Head % acquired Ticket Lock ^", headDat->groupNumber);
		int shortestTCLine = 0;
		int shortestTCLineLength = 256;

		////Print("Head %^",headDat->groupNumber);
		for (int i=0; i< MAX_TC ; i++) {
			// check for Available Ticket Clerk with the shortest length
			if ((shortestTCLineLength >= ticketClerkLineCount[i]) && 
				(ticketClerkState[i] != BREAK)) {
					shortestTCLineLength = ticketClerkLineCount[i];
					shortestTCLine = i;
			}
		}
		// shortest line found

		//Print("TC Line length = % ^", shortestTCLineLength);
		availTicketClerk = shortestTCLine;
		if ( availTicketClerk != NOCLERK) {

			ticketClerkLineCount[availTicketClerk]++;
			if (shortestTCLineLength >0) {
				// Head gets into the wait queue of the shortest queue ticket clerk
				//ticketClerkLineCount[availTicketClerk]++;
				//Print("Head % increased the line count %^",headDat->groupNumber,ticketClerkLineCount[availTicketClerk]);
				//wait for signal from TC using  line lock
				//Print("Head % waiting for TC ^", headDat->groupNumber);
				//keep
				//Print("Customer % in Group % is getting in TicketClerk line %^",headDat->customerNumber,  headDat->groupNumber, availTicketClerk);
				WaitCV(ticketClerkLineCV[availTicketClerk],ticketClerkLineLock);
			}
			if ( ticketClerkState[availTicketClerk] != BREAK) {
				//ticketClerkLineCount[availTicketClerk]++;
				ReleaseLock(ticketClerkLineLock);
				// Once woken up by the Ticket Clerk, buy tickets
				AcquireLock(ticketClerkLock[availTicketClerk]);
				numberTicketsPerTicketClerk[availTicketClerk] = headDat->groupSize;
				//Print("Head signalling TC for processing^");
				//keep
				//Print("Customer % in Group % is walking up to TicketClerk % to buy % tickets^",headDat->customerNumber,  headDat->groupNumber, availTicketClerk,headDat->groupSize);
				SignalCV(ticketClerkCV[availTicketClerk],ticketClerkLock[availTicketClerk]);
				// after passing on the ticket number, head customer waits

				WaitCV(ticketClerkLock[ticketClerkCV[availTicketClerk],availTicketClerk]);
				//keep
				//Print("Customer % in Group % in TicketClerk line % is paying % for tickets^",headDat->customerNumber,  headDat->groupNumber, availTicketClerk,headDat->groupSize*TICKETPRICE);
				//keep
				//Print("Customer % in Group % is leaving TicketClerk %^",headDat->customerNumber,  headDat->groupNumber, availTicketClerk);
				ReleaseLock(ticketClerkLock[availTicketClerk]);
			}
			else {
				//Print("**Head % searching again as TC % on break ^", headDat->groupNumber,availTicketClerk);
				//keep
				//Print("Customer % in Group % sees TicketClerk % is on break.^",headDat->customerNumber,  headDat->groupNumber, availTicketClerk);
				availTicketClerk = NOCLERK;
				//shortestTCLineLength = 256;
				ReleaseLock(ticketClerkLineLock);
			}
		}
		else {
			//Print("No TC found ^ ");
			//shortestTCLineLength = ticketClerkLineCount[0];
			ReleaseLock(ticketClerkLineLock);
		}

	}//while
}

void enterCinema(int data){ //groupSize == 0 means he is the member
	CustomerData* custData = (CustomerData*)data;
	int groupSize = custData->groupSize;
	int custGroupNumber = custData->groupNumber;
	int custCustomerNumber = custData->customerNumber;
	Print("Customer % in Group % has entered the movie theater^", 52, custCustomerNumber, custGroupNumber);
	if(groupSize > 0){
		//-------------HEAD AFTER ENTERING CINEMA--------------//
		//int seatPosition[groupSize][2];//recorded the seats picked up
		//if seatPosition[groupSize][0] or seatPosition[groupSize][1] equal to -1 means the seats have been picked up
		/**find best seats for group**/
		AcquireLock(Customer_Seats_Lock);
		int i;
		for(i=0;i < GROUP_SIZE; i++){
			custData->custGroupData->seatPositionForGroup[i][0] = -1;
			custData->custGroupData->seatPositionForGroup[i][1] = -1;
		}
		PickUpSeats(SeatPosition, 5, 5, groupSize, custData->custGroupData->seatPositionForGroup);

		//Customer [customerNumber] in Group [groupNumber] has found the following seat: row [rowNumber] and seat [seatNumber];

		//Print("Customer % in Group % has found the following seat: ^", custCustomerNumber, custGroupNumber);

		for(i=0;i < GROUP_SIZE; i++){
			//Print("row % and seat %^", custData->custGroupData->seatPositionForGroup[i][0], custData->custGroupData->seatPositionForGroup[i][1]);
		}

		NumOfOccupiedSeat = NumOfOccupiedSeat + groupSize;

		//Start to regroup: each member will wait for Movie Start and End CV rather than Group CV
		//Customer_MovieBegin_Lock->AcquireLock();

		//Print("Group% Leader broadcast to tell member to get a seat and wait for movie begin^", custGroupNumber);
		custData->custGroupData->lock->AcquireLock();
		custData->custGroupData->event->SignalCV(custData->custGroupData->lock);
		//Print("Group % Leader wait until all member sit down^",custData->groupNumber);
		//currentThread->Yield();
		custData->custGroupData->event->WaitCV(custData->custGroupData->lock);//ensure everybody sit down before he start waiting movie
		custData->custGroupData->lock->ReleaseLock();

		AcquireLock(Customer_MovieEnd_Lock);			//Print("Group Leader sit down^");
		ReleaseLock(Customer_Seats_Lock);//Release the seat lock, so that mgr will tell MT to start movie

		/**wait for movie begin**/

		BeginWatchMovie();

		/**wait for movie end**/
		//Print("Group% Leader wait for MOVIE END^",custGroupNumber);
		WaitCV(MovieEndCV,Customer_MovieEnd_Lock);
		AcquireLock(Customer_Seats_Lock);
		NumOfOccupiedSeat = NumOfOccupiedSeat - groupSize;//Leave their seats
		ReleaseLock(Customer_Seats_Lock);
		//Start to regroup
		//Print("Group Start to REGROUP on seat^");

		ReleaseLock(Customer_MovieEnd_Lock);

		/**regroup and go out of cinema and go to Lobby**/
		//Print("Group LEAVE^");
		custData->custGroupData->lock->AcquireLock();
		custData->custGroupData->event->BroadcastCV(custData->custGroupData->lock);//ensure everybody leaves the theatre
		custData->custGroupData->lock->ReleaseLock();
		//-------------AFTER LEAVING CINEMA--------------//

		/**Bathroom part**/
		//Head go to bathroom
		for (int i=1; i<custData->groupSize; i++) {
			custData->custGroupData->semaphore->P();
		}

		/**Leave cinema**/
	}


	else if(groupSize <= 0){

		/*Every member is supposed to wait on grouplock until leader get the seats*/
		//Print("Member % under Group % taking a seat ^", custData->customerNumber, custData->groupNumber);
		custData->custGroupData->lock->AcquireLock();
		custData->custGroupData->event->WaitCV(custData->custGroupData->lock);//----->3
		int SeatX = -1, SeatY = -1;
		/*for(int i = 0; i < custData->groupSize; i++){
		if(custData->custGroupData->seatPositionForGroup[i][0] >= 0 &&
		custData->custGroupData->seatPositionForGroup[i][1] >= 0){
		SeatX = custData->custGroupData->seatPositionForGroup[i][0];
		SeatY = custData->custGroupData->seatPositionForGroup[i][1];
		custData->custGroupData->seatPositionForGroup[i][0] = -1;
		custData->custGroupData->seatPositionForGroup[i][1] = -1;
		}
		break;
		}*/
		//Print("Member % under Group % taking a seat ^", custData->customerNumber, custData->groupNumber);
		//keep
		//Print("Customer % in group % is sitting in a theater room seat.^",custData->customerNumber, custData->groupNumber);

		/*DeGroup: everyone seat on seat and wait for movie beginning.*/
		AcquireLock(Customer_MovieEnd_Lock);
		//Print("Customer% gets a seat and wait for MOVIE START^",custCustomerNumber);
		//Print("Customer % in Group % has taken seat in movie theatre ^", custData->customerNumber, custData->groupNumber);
		custData->custGroupData->event->SignalCV(custData->custGroupData->lock);//tell the next customer. the final one should be the leader
		custData->custGroupData->lock->ReleaseLock();
		/*wait for movie end*/

		WaitCV(MovieEndCV,Customer_MovieEnd_Lock);
		ReleaseLock(Customer_MovieEnd_Lock);

		/*Regroup again*/
		custData->custGroupData->lock->AcquireLock();
		//Print("Customer% BACK TO GROUP^",custCustomerNumber);
		custData->custGroupData->event->WaitCV(custData->custGroupData->lock);
		//Print("Customer%  out of bathroom^",custCustomerNumber);
		custData->custGroupData->semaphore->V();
		custData->custGroupData->lock->ReleaseLock();
	}


}


//MOVIE TECHNICIAN
void movieTechnician(int l)
{

	while (1)
	{
		//MT must wait for manager to tell him to start the movie here
		//Print("movie Technician created^");
		AcquireLock(managerTellsMT_startMovieLock);
		WaitCV(managerTellsMT_startMovie_CV,managerTellsMT_startMovieLock);


		ReleaseLock(managerTellsMT_startMovieLock);

		//tell customer the movie begins
		//Customer_MovieBegin_Lock->AcquireLock();
		////Print("tell customer the movie begins^");
		//MovieBeginCV->BroadcastCV(Customer_MovieBegin_Lock);
		//MovieBeginCV->WaitCV(Customer_MovieBegin_Lock);//wait for customer to get ready, means let customer to get Customer_Seats_Lock and sleep first
		//Customer_MovieBegin_Lock->ReleaseLock();


		//start & play the movie here
		AcquireLock(Customer_MovieEnd_Lock);
		//Print("The MovieTechnician has started the movie.^");


		PlayMovie(); // only if all customers are seated.


		//after movie is finished, broadcast all customers that movie is over
		//Print("The MovieTechnician has ended the movie.^");
		//Print("The MovieTechnician has told all customers to leave the theater room.^");
		BroadcastCV(MovieEndCV,Customer_MovieEnd_Lock);



		ReleaseLock(Customer_MovieEnd_Lock);

		Fork(MovieTechnician);
	}

}


void initialCV(){
	int i;
	//Manager
	//NumOfOccupiedSeat = 0; //updated by customers only when they sit
	Customer_Seats_Lock = createLock("Lock: Customer_Seat_Lock", 24); //ALREADY DEFINED ABOVE, protects above value

	//SeatLeft = 0; // updated by TTs. tells how many cust were allowed into the theater.
	ticketTakerSeatLock = createLock("Lock: ticketTakerSeatLock", 25);


	managerTellsMT_startMovie_CV = createCV("CV: Mgr tell MT to Start Movie ", 31);
	managerTellsMT_startMovieLock = createLock("Lock: Mgr tell MT to Start Movie ", 33);

	MovieEndCV = createCV("CV: Movie End", 13);
	Customer_MovieEnd_Lock = createLock("Lock: Movie End", 15);

	MovieBeginCV = createCV("CV: Movie Begin", 15);
	Customer_MovieBegin_Lock = createLock("Lock: Movie Begin", 17);
	//Cus
	for(i = 0; i < MAX_TT; i++) ticketTakerCV[i] = createCV("Condition: ticketTakerCV", 24);
	for(i = 0; i < MAX_TT; i++) ticketTakerLock[i] = createLock("Lock: ticketTakerLock", 21);
	//ticketTakerState[MAX_TT];


	for(i = 0; i < MAX_TT; i++) ticketTakerLineCV[i] = createCV("Condition: ticketTakerLineCV", 28);
	ticketTakerLineLock = createLock("Lock: ticketTakerLineLock", 25);
	//ticketTakerLineCount[MAX_TT];

	for(i = 0; i < MAX_TT; i++) startTakingTicketCV = createCV("Condition: startTakingTicketCV", 30);
	startTakingTicketLock = createLock("Lock: startTakingTicketLock ", 28);
	//MgrTCNote[MAX_TT];//Manager leaves a note to tell him to break

	NextMovieIsReady_Customer_CV = createCV("Condition: NextMovieIsReady_Customer_CV", 39); //Manager tell customer in lobby to come and check tickets
	Customer_Lobby_Lock = createLock("Lock: Customer_Lobby_Lock ", 26); //Lock the customer by Lobby door


	/**initialize TT status**/
	for(i = 0; i < MAX_TT; i++){
		ticketTakerState[i] = BUSY;
	}

}




//The customer/headCustomer thread functions look like this at the top

void customer ( int data ) {
	//Cast the int argument back to a CustomerData poniter
	////Print("Creating Customers ^");
	CustomerData* custData = (CustomerData*)data;
	int food =0;
	int soda =0;


	//Now store the values in simple int variables to make the code
	//easier to read
	int custGroupNumber = custData->groupNumber;
	int custCustomerNumber = custData->customerNumber;

	if (custData->groupSize != 0){
		// Head Customer
		CustomerData *headData = custData;
		int custGroupSize = custData->groupSize;

		// wait for all the regular customer threads to create
		for (int i=1; i<headData->groupSize; i++) {
			headData->custGroupData->semaphore->P();
		}

		// find the ticketClerk and buy tickets
		//Print("Group %  buying tickets ^", custGroupNumber);
		buyTickets((int)headData);
		//Print("Head % Back after buying tickets & prompting members^",custGroupNumber);
		custData->custGroupData->lock->AcquireLock();
		custData->custGroupData->event->BroadcastCV(custData->custGroupData->lock);//--->1
		custData->custGroupData->lock->ReleaseLock();
		//wait for all the regular customers to provide orders		
		for (int i=1; i<headData->groupSize; i++) {
			headData->custGroupData->semaphore->P();
		}
		// randomise these values also
		//Head takes order from members
		//Print("Customer Number % ^",headData->customerNumber);
		//Print("Head % taking food soda order^",headData->groupNumber);
		int totFood = headData->custGroupData->food+1;
		int totSoda = headData->custGroupData->soda+1;
		buyFoodSoda((int)headData);
		//Print("Head % Back after food soda order^",headData->groupNumber);
		checkTicket(headData); //----->2
		Yield();
		Yield();
		enterCinema(data);

		//Print("Head % has left the movie theatre ^",headData->groupNumber);

	}
	else{
		//keep
		////Print("Customer % in Group % has entered the movie theater ^",custData->customerNumber,custData->groupNumber);

		custData->custGroupData->lock->AcquireLock();
		custData->custGroupData->semaphore->V();
		// wait for Head to Signal for order
		custData->custGroupData->event->WaitCV(custData->custGroupData->lock);//---->1 for food order
		//Print("Readyforfood % after wait 1^", custData->customerNumber);
		//probability
		food++;
		soda++;
		custData->custGroupData->food += food;
		custData->custGroupData->soda += soda;
		//Print("Customer % in Group % has % popcorn and % soda request from a group member^",custData->customerNumber,custData->groupNumber,food,soda);
		//keep
		//Print("Customer % in group % wants % popcorn and % soda.^",custData->custGroupData->food,custData->custGroupData->soda);
		custData->custGroupData->semaphore->V(); // prompt head Customer for order
		// customer member waiting for leader to finish check Ticket
		checkTicket(custData);
		//code for entering movie theatre
		//Print("Readyformovie %^", custData->customerNumber);
		//Print("Customer % in Group % has entered the movie theatre ^", custData->customerNumber, custData->groupNumber);
		enterCinema(data);

		// Acquire the movie theatre and wait on the condition that movie will get over
		//keep
		//Print("Customer % in Group % has left the movie theatre ^", custData->customerNumber, custData->groupNumber);


	}
}

//Make the number of groups random and the number in a group random.
// There can be up to 10 groups and a group can have from 1 to 5 members


//A global variable, nextCustomerNumber will work.
//Initialize this number to 0 (declare it in system.h/system.cc.

int nextCustomerNumber = 0;

void createCustomerGroups() {

	Customer_Lobby_Lock = createLock("LOBBY LOCK", 10);
	NextMovieIsReady_Customer_CV = createCV("NEXT MOVIE START CONDITION", 26);
	//int numberOfGroups = rand()%10 + 1;
	int numberOfGroups = NUM_GROUPS;

	//printf ("Number of groups = % ^" , numberOfGroups);
	for ( int i=0; i<numberOfGroups; i++ ) {
		//Generate the size of the group, not counting head customer

		//Print("Creating Group - Head % ^ ",i);
		int groupSize = GROUP_SIZE;
		//printf ("Groups Size = % ^" , groupSize);


		GroupData *grpData = new GroupData;
		grpData->event = createCV("Group1", 6);
		grpData->lock = createLock("Group1", 6);
		grpData->semaphore = new Semaphore("Group1",0);
		grpData->food = 0;
		grpData->soda = 0;
		grpData->ticketsTaken = 0;

		//Create and fork the head customer thread
		//The head customer of a group needs a group number, group size, 
		//and a customer number. I will store all 3 values in a struct pointer and pass
		//it as the second argument to Fork

		CustomerData *current = new CustomerData;
		current->customerNumber = nextCustomerNumber;
		nextCustomerNumber++; //don't need a lock as only this main thread does this
		current->groupNumber = i;
		current->groupSize = groupSize;
		current->custGroupData = grpData;

		//Thread *t = new Thread("Head Customer");
		Fork(customer);
		////Print("Head cust thread created ^");

		//Now make all the regular Customers for this group
		for ( int j=1; j<groupSize; j++ ) {
			////Print("Reg cust threads created % ^" , j);
			CustomerData *current = new CustomerData;
			current->customerNumber = nextCustomerNumber;
			nextCustomerNumber++;
			current->groupNumber = i;
			current->groupSize = 0;
			current->custGroupData = grpData;

			//Thread *t = new Thread("Regular Customer");
			Fork( customer);
		}

	}
	Exit(0);
}
// end createCustomerGroups


//----------------------------
// TICKET CLERK IMPLEMENTATION
//----------------------------

void ticketClerk( int tcIndex) {

	//Print("TC % created ^", tcIndex);

	while (1) {

		//Check if he needs to go on break
		//check the break status variable
		AcquireLock(MgrTCLock);
		if(MgrTCNote[tcIndex] == BREAK){
			AcquireLock(ticketClerkLock[tcIndex]);
			AcquireLock(ticketClerkLineLock);
			ticketClerkState[tcIndex] = BREAK;
			ticketClerkLineCount[tcIndex] = 0;
			BroadcastCV(ticketClerkLineCV[tcIndex],ticketClerkLineLock);
			ReleaseLock(ticketClerkLineLock);
			//keep
			//Print("TicketClerk % is going on break.^",tcIndex);
			WaitCV(MgrTCCondition,MgrTCLock); // Wait to come back from break
			//Print("TicketClerk % is coming off break.^",tcIndex);
			MgrTCNote[tcIndex] = NOBREAK;
			//if ( ticketClerkState[tcIndex] == BREAK) 
			//	ticketClerkState[tcIndex] = FREE;
		}
		//ticketClerkLineLock->ReleaseLock();//Release Line Lock    -----> M
		ReleaseLock(MgrTCLock);

		//Check if there is a customer in line
		AcquireLock(ticketClerkLineLock);
		//Print("*****TC % acquired line lock ^", tcIndex);

		if(ticketClerkLineCount[tcIndex] > 0) {
			//Customers are in line so set the Ticket Clerk state to busy (1) 
			//Decrement the line counter and wake up Customer Thread
			//Print("Line count more than 0 - % ^", ticketClerkLineCount[tcIndex]);
			ticketClerkState[tcIndex] = BUSY;
			ticketClerkLineCount[tcIndex]--;
			// signal to head using line lock
			//Print(" TC signalling customer ^");
			//keep
			//Print("TicketClerk % has a line length % and is signaling a customer.^",tcIndex,ticketClerkLineCount[tcIndex]);

			SignalCV(ticketClerkLineCV[tcIndex],ticketClerkLineLock);
		}
		else {
			//No Customers in line and Ticket Clerk is available
			ticketClerkState[tcIndex] = FREE;
			//keep
			//Print("TicketClerk % has no one in line. I am available for a customer.^",tcIndex);
		}
		AcquireLock(ticketClerkLock[tcIndex]);
		ReleaseLock(ticketClerkLineLock);
		//Wait for Customer to come to counter
		WaitCV(ticketClerkCV[tcIndex],ticketClerkLock[tcIndex]);
		//Print("Processing tickets % by TC %^", numberTicketsPerTicketClerk[tcIndex], tcIndex);
		//Print("TicketClerk % has an order for % and the cost is %.^",tcIndex,numberTicketsPerTicketClerk[tcIndex],numberTicketsPerTicketClerk[tcIndex]*TICKETPRICE);
		ticketsSoldPerTicketClerk[tcIndex] += numberTicketsPerTicketClerk[tcIndex];
		// add steps to take the number of tickets and get cash
		//for (int i=0; i<10;i++);
		SignalCV(ticketClerkCV[tcIndex],ticketClerkLock[tcIndex]);
		ReleaseLock(ticketClerkLock[tcIndex]);
		//before it goes on break it must process the Customer that is waiting on the ticketCLerk lock
		Yield();
	}//while
}


void createTicketClerk() {

	for(int i =0; i<MAX_TC; i++) {
		ticketClerkLineCV[i] = createCV("TC Line CV", 10);
		ticketClerkCV[i] = createCV("TC CV", 5);
		ticketClerkLock[i] = createLock("TC Lock", 7);
		ticketClerkLineLock = createLock("TC Line Lock", 12);
		ticketClerkState[i] = FREE;
		ticketClerkLineCount[i] = 0;
		numberTicketsPerTicketClerk[i] = 0; // number of tickets the customer wants
		//numberTicketsSold[i] = 0;
		ticketsSoldPerTicketClerk[i] = 0;
		MgrTCNote[i] = NOBREAK;
	}


	MgrTCCondition = createCV("Mgr TC Break Condition", 22);
	MgrTCLock = createLock("Mgr TC Break Lock", 17);

	//for(int i=0; i<MAX_TC; i++) {
	//	Thread *t = new Thread("TC");
		Fork(ticketClerk);
	//}
		Exit(0);
}

//----------------------------
// CONCESSION CLERK IMPLEMENTATION
//----------------------------

void concessionClerk( int ccIndex) {

	//Print("CC % created ^", ccIndex);

	while (1) {

		//Check if he needs to go on break
		//Print("*******CC % checking note ^", ccIndex);
		//check the break status variable
		AcquireLock(MgrCCLock);
		//Print("*******count % ^", concessionClerkLineCount[ccIndex]);

		if(MgrCCNote[ccIndex] == BREAK){
			//Print("******CC on break ^");
			AcquireLock(concessionClerkLock[ccIndex]);

			//Print("******CC waiting on note lock ^");

			AcquireLock(concessionClerkLineLock);
			concessionClerkState[ccIndex] = BREAK;
			concessionClerkLineCount[ccIndex] = 0;
			BroadcastCV(concessionClerkLineCV[ccIndex],concessionClerkLineLock);
			ReleaseLock(concessionClerkLineLock);
			//Print("ConcessionClerk % is going on break.^",ccIndex);
			WaitCV(MgrCCCondition,MgrCCLock); // Wait to come back from break
			MgrCCNote[ccIndex] = NOBREAK;
			//Print("ConcessionClerk % is coming off break.^",ccIndex);
			//if ( ticketClerkState[tcIndex] == BREAK) 
			//	ticketClerkState[tcIndex] = FREE;
		}
		//Print("*******CC % releasing line lock ^", ccIndex);
		//ticketClerkLineLock->ReleaseLock();//Release Line Lock    -----> M
		ReleaseLock(MgrCCLock);

		//Check if there is a customer in line
		AcquireLock(concessionClerkLineLock);
		//Print("*****CC % acquired line lock ^", ccIndex);

		if(concessionClerkLineCount[ccIndex] > 0) {
			//Customers are in line so set the Ticket Clerk state to busy (1) 
			//Decrement the line counter and wake up Customer Thread
			//Print("Line count more than 0 - % ^",concessionClerkLineCount[ccIndex]);
			concessionClerkState[ccIndex] = BUSY;
			concessionClerkLineCount[ccIndex]--;
			// signal to head using line lock
			//Print(" CC signalling customer ^");
			//keep
			//Print("ConcessionClerk % has a line length % and is signaling a customer.^",ccIndex,concessionClerkLineCount[ccIndex]);

			SignalCV(concessionClerkLineCV[ccIndex],concessionClerkLineLock);
		}
		else {
			//No Customers in line and Ticket Clerk is available
			concessionClerkState[ccIndex] = FREE;
		}
		AcquireLock(concessionClerkLock[ccIndex]);
		ReleaseLock(concessionClerkLineLock);
		//Wait for Customer to come to counter
		//keep
		//Print("ConcessionClerk % has no one in line. I am available for a customer.^",ccIndex);

		WaitCV(concessionClerkCV[ccIndex],concessionClerkLock[ccIndex]);
		//keep
		//Print("ConcessionClerk % has an order for % popcorn and % soda. The cost is %.^", ccIndex,foodQtyPerConcessionClerk[ccIndex],sodaQtyPerConcessionClerk[ccIndex], foodQtyPerConcessionClerk[ccIndex] * FOODPRICE + sodaQtyPerConcessionClerk[ccIndex] * SODAPRICE);

		//Print("Processing food soda order by CC %^", ccIndex);
		SignalCV(concessionClerkCV[ccIndex],concessionClerkLock[ccIndex]);
		//keep
		//Print("ConcessionClerk % has been paid for the order.^",ccIndex);


		ReleaseLock(concessionClerkLock[ccIndex]);
		//before it goes on break it must process the Customer that is waiting on the ticketCLerk lock
		Yield();
	}//while

	Exit(0);
}


void createConcessionClerk() {

	for(int i =0; i<MAX_CC; i++) {
		concessionClerkLineCV[i] = createCV("CC Line CV", 10);
		concessionClerkCV[i] = createCV("CC CV", 5);
		concessionClerkLock[i] = createLock("CC Lock", 7);
		concessionClerkLineLock = createLock("CC Line Lock", 12);
		concessionClerkState[i] = FREE;
		concessionClerkLineCount[i] = 0;
		numberTicketsPerTicketClerk[i] = 0; // number of tickets the customer wants
		//numberTicketsSold[i] = 0;
		ticketsSoldPerTicketClerk[i] = 0;
		MgrCCNote[i] = NOBREAK;
	}


	MgrCCCondition = createCV("Mgr CC Break Condition", 22);
	MgrCCLock = createLock("Mgr CC Break Lock", 17);

	//for(int i=0; i<MAX_CC; i++) {
	//	Thread *t = new Thread("CC");
		Fork(concessionClerk);
	//}
		Exit(0);
}

void ticketTakerStopTicket(int ttIndex) {

	//Print("Not taking tickets^");
	AcquireLock(ticketTakerLineLock);
	ticketTakerState[ttIndex] = STOP_TAKE_TICKET;
	//Print("TT % Broadcasting to the waiting threads ^", ttIndex);
	BroadcastCV(ticketTakerCV[ttIndex],ticketTakerLock[ttIndex]);//broadcast to customer on the line to go to lobby
	ticketTakerLineCount[ttIndex] = 0;
	ReleaseLock(ticketTakerLineLock);
	ReleaseLock(ticketTakerSeatLock);
	//Print("No room for customers^");
	AcquireLock(startTakingTicketLock);
	WaitCV(startTakingTicketCV,startTakingTicketLock);//put himself to wait for next movie start.

	//----------------------------------------------------------------------
	// TT START to take ticket after waken up by Manager
	//----------------------------------------------------------------------
	//TT will reset my state in the next loop
	ReleaseLock(startTakingTicketLock);
}


//We suppose that TT always grab the line lock first when he first time come to take ticket
void ticketTaker(int ttIndex) { //add1

	//Print("TT % created ^", ttIndex);

	while (1) {
		AcquireLock(ticketTakerLineLock); // always grab the line lock first
		//Print("*****TT % acquired line lock ^", ttIndex);

		//Check if to BREAK OR STOP by manager
		//Print("*******TT % checking note ^", ttIndex);
		//check the break status variable
		AcquireLock(MgrTTLock);
		//Print("*******count % ^", ticketTakerLineCount[ttIndex]);

		if(MgrTTNote[ttIndex] == BREAK){
			//Print("******TT on break with % customers ^",ticketTakerLineCount[ttIndex]);
			AcquireLock(ticketTakerLock[ttIndex]);
			ticketTakerState[ttIndex] = BREAK;
			ticketTakerLineCount[ttIndex] = 0;
			//Print("TT % line count % ^",ttIndex,ticketTakerLineCount[ttIndex]);
			//Print("TT % broadcasts on line ^", ttIndex);
			BroadcastCV(ticketTakerLineCV[ttIndex],ticketTakerLineLock);

			ReleaseLock(ticketTakerLineLock);
			//Print("******TT waiting on note lock ^");
			//Print("TicketTaker % is going on break.^",ttIndex);

			WaitCV(MgrTTCondition,MgrTTLock); // Wait to come back from break
			//Print("TicketTaker % is coming off break.^",ttIndex);

			MgrTTNote[ttIndex] = NOBREAK;
		}
		else if(MgrTTNote[ttIndex] == STOP_TAKE_TICKET){
			//Print("TicketTaker % is not allowing the group into the theater as the Manager ordered to stop %.^",ttIndex);
			MgrTTNote[ttIndex] = NOBREAK;

			//Print("Not taking tickets^");
			ticketTakerState[ttIndex] = STOP_TAKE_TICKET;
			//Print("TT % Broadcasting to the waiting threads ^", ttIndex);
			BroadcastCV(ticketTakerCV[ttIndex],ticketTakerLock[ttIndex]);//broadcast to customer on the line to go to lobby
			ticketTakerLineCount[ttIndex] = 0;
			ReleaseLock(ticketTakerLineLock);
			//Print("Manager order me not to take tickets!^");
			AcquireLock(startTakingTicketLock);
			WaitCV(startTakingTicketCV,startTakingTicketLock);//put himself to wait for next movie start.

			//----------------------------------------------------------------------
			// TT START to take ticket after waken up by Manager
			//----------------------------------------------------------------------
			//TT will reset my state in the next loop
			ReleaseLock(startTakingTicketLock);
			ReleaseLock(ticketTakerLock[ttIndex]);
		}

		//Print("*******TT % releasing line lock ^", ttIndex);
		//ticketClerkLineLock->ReleaseLock();//Release Line Lock    -----> M
		ReleaseLock(MgrTTLock);




		//TT Set his STATUS

		//----------------------------------------------------------------------
		// TT STOP taking Ticket if no more room left
		//    CONTINUE if still room left
		//----------------------------------------------------------------------

		if(ticketTakerLineCount[ttIndex] > 0) {
			//Customers are in line so set the Ticket taker state to busy (1) 
			//Print("Line count more than 0 - % ^", ticketTakerLineCount[ttIndex]);
			ticketTakerState[ttIndex] = BUSY;
			ticketTakerLineCount[ttIndex]--;
			// signal to head using line lock
			//Print(" TT signalling customer ^");
			//keep
			//Print("TicketTaker % has a line length % and is signaling a customer.^",ttIndex,ticketTakerLineCount[ttIndex]);

			SignalCV(ticketTakerLineCV[ttIndex],ticketTakerLineLock);
		}
		else {
			//No Customers in line and Ticket Clerk is available
			ticketTakerState[ttIndex] = FREE;
			//keep
			//Print("TicketTaker % has no one in line. I am available for a customer.^",ttIndex);

			/*ticketTakerLock[ttIndex]->AcquireLock();
			//Print("TT % acquired Ticket Taker Lock ^", ttIndex);
			ticketTakerLineLock->ReleaseLock();
			//Wait for Customer to come to counter
			//Print(" TT % wait for customer ^", ttIndex);
			//wait for customer to set groupsize(number of ticket) into TicketTakenPerGroup
			ticketTakerCV[ttIndex]->WaitCV(ticketTakerLock[ttIndex]);

			//tell customer you can go to cinema
			ticketTakerCV[ttIndex]->SignalCV(ticketTakerLock[ttIndex]);

			ticketTakerLock[ttIndex]->ReleaseLock();
			continue;*/
		}


		AcquireLock(ticketTakerLock[ttIndex]);

		ReleaseLock(ticketTakerLineLock);


		//Wait for Customer to come to counter
		//wait for customer to set groupsize(number of ticket) into TicketTakenPerGroup
		WaitCV(ticketTakerCV[ttIndex],ticketTakerLock[ttIndex]);
		//Print("TicketTaker % has received % tickets.^",ttIndex,numberTicketsPerTicketTaker[ttIndex]);

		//before let customer in or not, check mgr's order first.
		AcquireLock(MgrTTLock);
		if(MgrTTNote[ttIndex] == STOP_TAKE_TICKET){
			//Print("TT % put to stop ^",ttIndex);
			MgrTTNote[ttIndex] = NOBREAK;

			//Print("Not taking tickets^");
			ticketTakerState[ttIndex] = STOP_TAKE_TICKET;
			//Print("TT % Broadcasting to the waiting threads ^", ttIndex);
			BroadcastCV(ticketTakerCV[ttIndex],ticketTakerLock[ttIndex]);//broadcast to customer on the line to go to lobby
			ticketTakerLineCount[ttIndex] = 0;
			//Print("Manager order me not to take tickets!^");
			AcquireLock(startTakingTicketLock);
			WaitCV(startTakingTicketCV,startTakingTicketLock);//put himself to wait for next movie start.

			//----------------------------------------------------------------------
			// TT START to take ticket after waken up by Manager
			//----------------------------------------------------------------------
			//TT will reset my state in the next loop
			ReleaseLock(startTakingTicketLock);
			ReleaseLock(ticketTakerLock[ttIndex]);
			continue;

			ReleaseLock(MgrTTLock);
			continue;
		}
		else{
			ReleaseLock(MgrTTLock);
			//ticketTakerLock[ttIndex]->ReleaseLock();

			//Print("TTProcessing tickets % by TT %^", numberTicketsPerTicketTaker[ttIndex], ttIndex);
			// add steps to take the number of tickets and get cash
			//for (int i=0; i<10;i++);

			AcquireLock(ticketTakerSeatLock);// checking the shared seat number left
			if (seatLeft >= numberTicketsPerTicketTaker[ttIndex]){ //CONTINUE: still room left

				//PRINT: take the ticket and let group into cinema, customer action: TicketTakenPerGroup[ttIndex] = GroupSize;
				AcquireLock(ticketTakerLineLock);
				ticketTakerState[ttIndex] = BUSY;
				ticketTakerLineCount[ttIndex]--;
				seatLeft -= numberTicketsPerTicketTaker[ttIndex];
				//update the remaining seats value


				SignalCV(ticketTakerCV[ttIndex],ticketTakerLock[ttIndex]); // allow the customer inside
				//keep
				//Print("TicketTaker % is allowing the group into the theater. The number of tickets taken is %.^", ttIndex,numberTicketsPerTicketTaker[ttIndex]);
				ReleaseLock(ticketTakerLineLock);
				ReleaseLock(ticketTakerLock[ttIndex]);
				ReleaseLock(ticketTakerSeatLock);


				if(seatLeft == 0){
					//Print("Not taking tickets^");
					ticketTakerState[ttIndex] = STOP_TAKE_TICKET;
					//Print("TT % Broadcasting to the waiting threads ^", ttIndex);
					BroadcastCV(ticketTakerCV[ttIndex],ticketTakerLock[ttIndex]);//broadcast to customer on the line to go to lobby
					ticketTakerLineCount[ttIndex] = 0;
					//Print("Manager order me not to take tickets!^");
					AcquireLock(startTakingTicketLock);
					WaitCV(startTakingTicketCV,startTakingTicketLock);//put himself to wait for next movie start.

					//----------------------------------------------------------------------
					// TT START to take ticket after waken up by Manager
					//----------------------------------------------------------------------
					//TT will reset my state in the next loop
					ReleaseLock(startTakingTicketLock);
					ReleaseLock(ticketTakerLock[ttIndex]);
					ReleaseLock(ticketTakerSeatLock);
					continue;
				}

			}
			else { //STOP: no room left for the next group

				//Print("Not taking tickets^");
				ticketTakerState[ttIndex] = STOP_TAKE_TICKET;
				//Print("TT % Broadcasting to the waiting threads ^", ttIndex);
				BroadcastCV(ticketTakerCV[ttIndex],ticketTakerLock[ttIndex]);//broadcast to customer on the line to go to lobby
				ticketTakerLineCount[ttIndex] = 0;
				//Print("Manager order me not to take tickets!^");
				AcquireLock(startTakingTicketLock);
				WaitCV(startTakingTicketCV,startTakingTicketLock);//put himself to wait for next movie start.

				//----------------------------------------------------------------------
				// TT START to take ticket after waken up by Manager
				//----------------------------------------------------------------------
				//TT will reset my state in the next loop
				ReleaseLock(startTakingTicketLock);
				ReleaseLock(ticketTakerLock[ttIndex]);
				ReleaseLock(ticketTakerSeatLock);
				continue;
			}
		}//while
	}
}

void createTicketTaker() {

	for(int i =0; i<MAX_TT; i++) {
		ticketTakerLineCV[i] = createCV("TT Line CV", 10);
		ticketTakerCV[i] = createCV("TT CV", 5);
		ticketTakerLock[i] = createLock("TT Lock", 7);
		ticketTakerLineLock = createLock("TT Line Lock", 12);
		ticketTakerState[i] = ABSENT;
		ticketTakerLineCount[i] = 0;
		numberTicketsPerTicketTaker[i] = 0; // number of tickets the customer wants
		//numberTicketsSold[i] = 0;
		MgrTTNote[i] = NOBREAK;
	}

	ticketTakerSeatLock = createLock("SEAT LOCK", 9);
	seatLeft = CINEMACAPACITY;
	startTakingTicketCV = createCV("TT START CONDITION", 18);
	startTakingTicketLock = createLock("TT START LOCK", 13); 

	MgrTTCondition = createCV("Mgr TC Break Condition", 22);
	MgrTTLock = createLock("Mgr TC Break Lock", 17);

	//for(int i=0; i<MAX_TT; i++) {
	//	Thread *t = new Thread("TT");
	Fork(ticketTaker);
	//}
}


int ticketCollection = 0;
int foodCollection = 0;
int sodaCollection = 0;

void mgr_TC(){
	/////-----------TICKET CLERK-----------
	int onbreak =0;
	for(int j=0; j<50000;j++);
	for (int tcIndex=0; tcIndex<MAX_TC; tcIndex++) {
		//20% break chance
		//srand((unsigned)time(0));

		// put the TC on break
		AcquireLock(ticketClerkLineLock);
		//Print("####Acquired Line Lock for TC %^",tcIndex);
		if( ! onbreak){
			if( ticketClerkState[tcIndex] != BREAK && ticketClerkLineCount[tcIndex] < 3 ) {
				//if(rand()%5 == 0)
				//Print("######Manager puts break note for TC %", tcIndex);
				AcquireLock(MgrTCLock);
				MgrTCNote[tcIndex] = BREAK;
				ReleaseLock(MgrTCLock);
				onbreak = 1;
			}
		}

		ReleaseLock(ticketClerkLineLock);
	}
	Yield();

	Yield();

	for (int tcIndex=0; tcIndex<MAX_TC; tcIndex++) {
		//Print("#####Manager checking line count ^");
		if ((ticketClerkLineCount[tcIndex] > 5) && (ticketClerkState[tcIndex] != BREAK))//check TCLineCount[]
		{
			//Loop through TCState array & Call breaking one BACK
			//Print("##### Line count more for TC % ^",tcIndex);
			AcquireLock(MgrTCLock);
			SignalCV(MgrTCCondition,MgrTCLock);
			ReleaseLock(MgrTCLock);
		}
	}


	for (int tcIndex=0; tcIndex<MAX_TC; tcIndex++) {
		//Print("####Manager collecting cash from Ticket Clerk ^");
		ticketCollection += ticketsSoldPerTicketClerk[tcIndex];
	}
	ticketCollection *=TICKETPRICE;
	//Print("Manager collected % from Ticket Clerk ^", ticketCollection);


	//Print("#####Inside Manager ^");

}

void mgr_CC(){
	/////----------CONCESSION CLERK----------
	/*for (int ccIndex=0; ccIndex<MAX_CC; ccIndex++) {
	//Print("####Manager collecting cash from Ticket Clerk ^");
	foodCollection += foodQtyPerConcessionClerk[ccIndex];
	sodaCollection += sodaQtyPerConcessionClerk[ccIndex];
	} 
	//Print("Manager collected % food and % soda from Concession Clerk ^", foodCollection,sodaCollection);
	*/
}


void mgr_TT_Break_BackToWork(){
	/////-----------TICKET TAKER-----------
	int is_ALL_TT_Queue_Still_Empty = 0;// each time check, will increase if empty
	int doMgrStartMovie = 0;

	//Not Start movie Yet
	if(doMgrStartMovie != 1){

		//================Put Break OR Get Back Work==================//
		/*Let Sb Take a Break!*/
		//Print("###Manager inside if^");
		int sbIsOnBreak = 0;

		//20% break chance
		//srand((unsigned)time(0));

		// put the TT on break
		AcquireLock(ticketTakerLineLock);
		//Print("####Acquired Line Lock for TT %^",ttIndex);


		for(int i = 0; i < MAX_TT; i++){
			if(ticketTakerState[i] == BREAK){
				sbIsOnBreak = 1;
				break;
			}
		}

		int numOfPeopleOnWork = 0;
		for(int i = 0; i < MAX_TT; i++){
			if(ticketTakerState[i] == BUSY || ticketTakerState[i] == FREE){
				numOfPeopleOnWork++;
			}
		}

		for (int ttIndex=0; ttIndex<MAX_TT; ttIndex++) {
			if( (!sbIsOnBreak) && numOfPeopleOnWork >= 2
				&& (ticketTakerState[ttIndex] == BUSY || ticketTakerState[ttIndex] == FREE)
				&& ticketTakerLineCount[ttIndex] < 3 ) {
					//if(rand()%5 == 0)
					//Print("######Manager puts break note for TT % with count % /n", ttIndex, ticketTakerLineCount[ttIndex]);
					AcquireLock(MgrTTLock);
					MgrTTNote[ttIndex] = BREAK;
					ReleaseLock(MgrTTLock);
					ReleaseLock(ticketTakerLineLock);
					sbIsOnBreak = 1;
					break; //only one employee among the same type can take a break each time
			}
		}

		/*Get Sb back to work!*/
		for (int j=0; j<11; j++)
			Yield();
		//for(int f=0; f<2; f++){
		for (int tcIndex=0; tcIndex<MAX_TT; tcIndex++) {
			AcquireLock(ticketTakerLineLock);
			//Print("#####Manager checking line count = % and tt % state = %^", ticketTakerLineCount[tcIndex],tcIndex, ticketTakerState[tcIndex]);
			if ((ticketTakerLineCount[tcIndex] >= QUEUE_LEN_GET_CLERK_BACK) && (ticketTakerState[tcIndex] != BREAK))//check TCLineCount[]
			{
				//Print("##### Line count more for TT % ^",tcIndex);

				//Loop through TCState array & Call breaking one BACK
				for(int k = 0; k < MAX_TT; k++){
					if(ticketTakerState[tcIndex] == FREE){
						AcquireLock(MgrTTLock);
						SignalCV(MgrTTCondition,MgrTTLock);
						ReleaseLock(MgrTTLock);
						ReleaseLock(ticketTakerLineLock);
						break;
					}
				}
			}
		}
	}
}

//***************************************************************************
//if all TT is Stopped/Break or TT's line is empty for a while, return 1;
//else return 0
//##### using GLOBAL VALUE: is_ALL_TT_Queue_Still_Empty
//***************************************************************************
int mgr_TT_ReadyForMovie(){
	//================Check if Need to start Movie==================//
	//global value: is_ALL_TT_Queue_Still_Empty:  each time check, will increase if empty
	int doTTReadyForMovie = 0;

	//***Check all ticketTakerState IF stop working
	int isAllTT_StoppedOrBreak = 1;
	for(int i = 0; i<MAX_TT; i++)
	{
		if(ticketTakerState[i] == FREE || ticketTakerState[i] == BUSY){
			isAllTT_StoppedOrBreak = 0;
			break;
		}
	}
	if(isAllTT_StoppedOrBreak){
		doTTReadyForMovie = 1;
		is_ALL_TT_Queue_Still_Empty = 0;		//reset counter
		return doTTReadyForMovie;
	}


	//***Check if all TT's line is empty
	else{

		int isAllQueueEmpty = 1;
		for(int i = 0; i<MAX_TT; i++){
			if(ticketTakerLineCount[i] != 0){
				isAllQueueEmpty = 0;
				break;
			}
		}

		if(isAllQueueEmpty == 1){
			is_ALL_TT_Queue_Still_Empty++;
			if(is_ALL_TT_Queue_Still_Empty == MGR_WAIT_LONG_TIME){
				//Print("==========================Manager: %^",is_ALL_TT_Queue_Still_Empty);
				is_ALL_TT_Queue_Still_Empty = 0;		//reset counter
				doTTReadyForMovie = 1;
			}
		}
	}

	//*** Stop some TT who still working
	if(doTTReadyForMovie == 1){


		for(int i = 0; i < MAX_TT; i++){
			//Print("=============manager: Stop some TT who still working^");
			if(ticketTakerState[i] != STOP_TAKE_TICKET && ticketTakerState[i] != BREAK
				&& ticketTakerState[i] != ABSENT){
					AcquireLock(ticketTakerLineLock);
					AcquireLock(MgrTTLock);
					MgrTTNote[i] = STOP_TAKE_TICKET;
					ReleaseLock(MgrTTLock);

					AcquireLock(ticketTakerLock[i]);
					ReleaseLock(ticketTakerLineLock);

					SignalCV(ticketTakerCV[i],ticketTakerLock[i]);
					ReleaseLock(ticketTakerLock[i]);
			}
		}
	}
	return 0; // put stop to all TT, need to loop this func again to check
}

//***************************************************************************
//manager will loop for checking if all customer seated
//if some customers never seat, then return 0
//***************************************************************************
int mgr_wait_CUS_ForMovieReady(){


	int isAllCustSeated = 0;

	////Print("NumOfOccupiedSeat: %^",NumOfOccupiedSeat);

	//	Customer_Seats_Lock->AcquireLock();
	//	ticketTakerSeatLock->AcquireLock();
	//Print("NumOfOccupiedSeat2: %^",NumOfOccupiedSeat);
	//int actuallySeatedCust = NumOfOccupiedSeat;

	//find if all seated
	//Print("seat left % occupied % ^",seatLeft,NumOfOccupiedSeat);
	if(seatLeft + NumOfOccupiedSeat == CINEMACAPACITY)
	{
		isAllCustSeated = 1;
		ReleaseLock(ticketTakerSeatLock);
		ReleaseLock(Customer_Seats_Lock);
		return isAllCustSeated;

	}
	//	ticketTakerSeatLock->ReleaseLock();
	//	Customer_Seats_Lock->ReleaseLock();

	return isAllCustSeated;
}

//***************************************************************************
//manager tell MT to start movie
//***************************************************************************
void mgr_MT_StartMovie(){
	AcquireLock(managerTellsMT_startMovieLock);	//Print("Manager is telling the MovieTechnnician to start the movie.^");
	SignalCV(managerTellsMT_startMovie_CV,managerTellsMT_startMovieLock); //Print("Manager to MT: Start Movie^");
	ReleaseLock(managerTellsMT_startMovieLock);
}

//***************************************************************************
//manager get seats ready for next Movie and tell TT
//and Customer in Lobby to wake up
//if Ready, return 1
//else return 0
//***************************************************************************
int mgr_GetNextMovieReady(){
	//***check if all customer leave
	//Print("manager wait everyone leave cinema^");
	//Customer_Seats_Lock->AcquireLock();
	if(NumOfOccupiedSeat > 0) {
		//Customer_Seats_Lock->ReleaseLock();
		for(int i =0; i < 5; i++)
			Yield();
		return 0;
	}
	else{

		if(NumOfOccupiedSeat == 0){
			Print("############## Manager: Time to start next movie^", 49, 0, 0);
		}
		else if(NumOfOccupiedSeat < 0){
			//Print("Seat Error: >1 people sit on same seat!^");
		}
		//Customer_Seats_Lock->ReleaseLock();

		//wake TT up
		AcquireLock(startTakingTicketLock);
		BroadcastCV(startTakingTicketCV,startTakingTicketLock);
		ReleaseLock(startTakingTicketLock);

		//wake customer up
		AcquireLock(Customer_Lobby_Lock);
		BroadcastCV(NextMovieIsReady_Customer_CV,Customer_Lobby_Lock);
		ReleaseLock(Customer_Lobby_Lock);
	}
	return 1;
}

void manager(int n){
	int movieRound;//record the number of movie: 1st time movie, 2nd movie, ...
	for(movieRound = 1; movieRound < 5; movieRound++){

		//*** loop for checking TC, CC and TT, Stop when all TT stop or TT's line empty for a while
		while(1){

			//TC
			mgr_TC();
			//CC

			mgr_TT_Break_BackToWork();
			if(mgr_TT_ReadyForMovie() == 1)
				break;
		}
		Yield();

		//*** wait for customer seat
		int errorCnt; //reach the limit will throw error
		int result1 = mgr_wait_CUS_ForMovieReady();
		for(errorCnt = 0; result1 == 0 && errorCnt < 1; errorCnt++){
			if(errorCnt == 500)
				Print("ERROR: manager - customer never seat^", 37, 0, 0);

			Yield();
			result1 = mgr_wait_CUS_ForMovieReady();
			Yield();
		}

		//*** call MT to start
		mgr_MT_StartMovie();
		Yield(currentThread);

		//*** wait for customer leaving
		int result2 = mgr_GetNextMovieReady();
		for(errorCnt = 0; result2 == 0 && errorCnt < 1; errorCnt++){
			if(errorCnt == 500)
				Print("ERROR: manager - customer never leave^", 38, 0, 0);

			Yield();
			result2 = mgr_GetNextMovieReady();
			Yield();
		}

		Yield();
		Print("Manager finish % movies^", 24, movieRound, 0);
		seatLeft = 0;
		NumOfOccupiedSeat = 0;

		Fork(manager);
	}
}

void manager2(int n) {

	/////-----------TICKET CLERK-----------
	mgr_TC();

	/////----------CONCESSION CLERK----------
	mgr_CC();

	///----------TICKET TAKER--------
	int is_ALL_TT_Queue_Still_Empty = 0;// each time check, will increase if empty
	int doMgrStartMovie = 0;
	//Print("####Manager checking for movie start^");

	while (1) {

		/*Put a Break or put back to Work*/
		int isAllQueueEmpty = 1;
		if(doMgrStartMovie != 1){
			//Print("###Manager inside if^");
			/*Let Sb Take a Break!*/
			int sbIsOnBreak = 0;
			for (int ttIndex=0; ttIndex<MAX_TT; ttIndex++) {
				//20% break chance
				//srand((unsigned)time(0));

				// put the TT on break
				AcquireLock(ticketTakerLineLock);
				//Print("####Acquired Line Lock for TT %^",ttIndex);


				for(int i = 0; i < MAX_TT; i++){
					if(ticketTakerState[ttIndex] == BREAK){
						sbIsOnBreak = 1;
						break;
					}
				}

				int numOfPeopleOnWork = 0;
				for(int i = 0; i < MAX_TT; i++){
					if(ticketTakerState[ttIndex] == BUSY || ticketTakerState[ttIndex] == FREE){
						numOfPeopleOnWork++;
					}
				}

				if( (!sbIsOnBreak) && numOfPeopleOnWork >= 2
					&& (ticketTakerState[ttIndex] == BUSY || ticketTakerState[ttIndex] == FREE)
					&& ticketTakerLineCount[ttIndex] < 3 ) {
						//if(rand()%5 == 0)
						//Print("######Manager puts break note for TT % with count % /n", ttIndex, ticketTakerLineCount[ttIndex]);
						AcquireLock(MgrTTLock);
						MgrTTNote[ttIndex] = BREAK;
						ReleaseLock(MgrTTLock);
						ReleaseLock(ticketTakerLineLock);
						break;
						//break one employee at a time
				}

				//ticketTakerLineLock->ReleaseLock();
			}




			/*Get Sb back to work!*/
			for (int j=0; j<11; j++)
				Yield();
			//for(int f=0; f<2; f++){
			for (int tcIndex=0; tcIndex<MAX_TT; tcIndex++) {
				AcquireLock(ticketTakerLineLock);
				//Print("#####Manager checking line count = % and tt % state = %^", ticketTakerLineCount[tcIndex],tcIndex, ticketTakerState[tcIndex]);
				if ((ticketTakerLineCount[tcIndex] >= 2) && (ticketTakerState[tcIndex] != BREAK))//check TCLineCount[]
				{
					//Loop through TCState array & Call breaking one BACK
					//Print("##### Line count more for TT % ^",tcIndex);
					AcquireLock(MgrTTLock);
					SignalCV(MgrTTCondition,MgrTTLock);
					ReleaseLock(MgrTTLock);
					ReleaseLock(ticketTakerLineLock);
					break;
				}
				//ticketTakerLineLock->ReleaseLock();
			}

		}

		//================Check if Need to start Movie==================//


		//Check all ticketTakerState IF STOP
		int isAllTT_StoppedOrBreak = 1;
		for(int i = 0; i<MAX_TT; i++)
		{
			if(ticketTakerState[i] != STOP_TAKE_TICKET && ticketTakerState[i] != BREAK){  //add1					{                                             //add1
				isAllTT_StoppedOrBreak = 0;
				break;
			}
		}
		if(isAllTT_StoppedOrBreak)
			doMgrStartMovie = 1;

		else{
			//Check if all TT's line is empty
			//int is_ALL_TT_Queue_Still_Empty =0;

			for(int i = 0; i<MAX_TT; i++)
			{
				if(ticketTakerLineCount[i] != 0)
				{
					isAllQueueEmpty = 0;
					break;
				}
			}

			if(isAllQueueEmpty == 1){
				is_ALL_TT_Queue_Still_Empty++;
				if(is_ALL_TT_Queue_Still_Empty == MGR_WAIT_LONG_TIME){
					doMgrStartMovie = 1;
					//Print("==========================Manager: %^",is_ALL_TT_Queue_Still_Empty);
				}
			}
		}                                    //add1

		if(doMgrStartMovie == 1){

			//Stop some TT who still working
			for(int i = 0; i < MAX_TT; i++){
				//Print("=============manager: Stop some TT who still working^");
				if(ticketTakerState[i] != STOP_TAKE_TICKET && ticketTakerState[i] != BREAK
					&& ticketTakerState[i] != ABSENT){
						AcquireLock(ticketTakerLineLock);
						AcquireLock(MgrTTLock);
						MgrTTNote[i] = STOP_TAKE_TICKET;
						ReleaseLock(MgrTTLock);

						AcquireLock(ticketTakerLock[i]);
						ReleaseLock(ticketTakerLineLock);

						SignalCV(ticketTakerCV[i],ticketTakerLock[i]);
						ReleaseLock(ticketTakerLock[i]);
				}
			}

			//Check if all TT STOP
			int doMgrCheckAgain = 0;
			for(int i = 0; i < MAX_TT; i++){
				//Print("=============manager: Check if all TT STOP^");
				//Print("TT % is % && doMgrCheckAgain: %^", i, ticketTakerState[i], doMgrCheckAgain);
				if(ticketTakerState[i] == BUSY || ticketTakerState[i] == FREE){
					doMgrCheckAgain = 1;

					break;
				}
			}
			for(int i = 0; i < 5; i++){
				Yield();
			}

			if(doMgrCheckAgain == 1)
				continue;
			//Start movie
			//Print("@@@@@@@@@@@@@@@@@@start movie!^");
			/*Movie Start*/
			//if all stopped then start signal MT to start the movie

			//Check If all Customer Seated
			int isAllCustSeated = 0;
			do
			{
				////Print("NumOfOccupiedSeat: %^",NumOfOccupiedSeat);
				//access variable here
				AcquireLock(Customer_Seats_Lock);
				//				//Print("NumOfOccupiedSeat2: %^",NumOfOccupiedSeat);
				//int actuallySeatedCust = NumOfOccupiedSeat;

				//find if all seated
				//Print("seat left % occupied % ^",seatLeft,NumOfOccupiedSeat);
				if(seatLeft + NumOfOccupiedSeat == CINEMACAPACITY)
				{
					isAllCustSeated = 1;
					break;
				}
				ReleaseLock(Customer_Seats_Lock);
				for(int i = 0; i < 5; i++)
					Yield();
			}
			while( isAllCustSeated == 0 );

			if(isAllCustSeated == 1)
			{
				//tell technician to start Movie
				AcquireLock(managerTellsMT_startMovieLock);	//Print("Manager is telling the MovieTechnnician to start the movie.^");
				SignalCV(managerTellsMT_startMovie_CV,managerTellsMT_startMovieLock); //Print("Manager to MT: Start Movie^");
				ReleaseLock(managerTellsMT_startMovieLock);

			}
			else
			{
				//Print("###MGR unable to start the movie^");
				//ERROR -- should not come here ever HACK
			}

			/*Movie End*/
			//Manager does not care when the movie end
			//But he does care when next movie should be ready
			/*Next Movie Ready*/
			//check if all customer leave
			//Print("manager wait everyone leave cinema^");
			while(NumOfOccupiedSeat > 0) { for(int i =0; i < 5; i++) Yield(); }
			if(NumOfOccupiedSeat == 0){
				//Print("Time to start next movie^");
			}
			if(NumOfOccupiedSeat < 0){
				//Print("Seat Error: >1 people sit on same seat!^");
			}
			if(doMgrStartMovie == 1){
				//Print("==============Manager succeed in starting movie!^");
				//wake TT up
				AcquireLock(startTakingTicketLock);
				BroadcastCV(startTakingTicketCV,startTakingTicketLock);
				ReleaseLock(startTakingTicketLock);

				//wake customer up
				AcquireLock(Customer_Lobby_Lock);
				BroadcastCV(NextMovieIsReady_Customer_CV,Customer_Lobby_Lock);
				ReleaseLock(Customer_Lobby_Lock);
			}


		}


	}


	is_ALL_TT_Queue_Still_Empty = 0;

}//manager


